#ifndef pkm_metagraphics_h
#define pkm_metagraphics_h

#include <list>
#include <vector>
#include "RenderObject.h"
#include "AbstractViewport.h"
#include "ConcreteViewport.h"
#include "ViewportLink.h"
#include "GraphicsInternals.h"
#include "Renderer.h"
#include "lua.hpp"

#define GRAPHICS_TABLE_SIZE 10000
#define GRAPHICS_LAYERS 10
#define MAX_VIEWPORTS 10
#define NUM_RENDERERS 10

#define DEFAULT_SW 800
#define DEFAULT_SH 600

namespace k2graphics
{

class Metagraphics
{
	Metagraphics();
	static Metagraphics* _theGraphics;

	// global list of graphics objects
	RenderObject* _renderObjects[GRAPHICS_TABLE_SIZE];
	std::list<int> _freeObjectSlots;
	std::vector<RenderObject*> _liveObjectList;

	// abstract viewports
	AbstractViewport* _abstractViewports[MAX_VIEWPORTS];

	// concrete viewport
	ConcreteViewport* _concreteViewports[MAX_VIEWPORTS];

	// links
	ViewportLink* _viewportLinks[MAX_VIEWPORTS];

	// graphics 'globals'
	GraphicsInternals* _gInternals;

	// renderers
	Renderer* _renderers[NUM_RENDERERS];

	// special font texture id
	//int _fontTexGLID;

	// colors for console
	//float* _conColors;
public:
	static Metagraphics* getMetagraphics()
	{
		if(_theGraphics)
			return _theGraphics;
		else
		{
			_theGraphics = new Metagraphics();
			return _theGraphics;
		}
	}

	// custom renderer stuff
	void addCustomRenderer(Renderer* r, int slot);

	////////////////////////////////////////
	// k3 SuperManager stuff
	//////////////////////////////////////////
	
	static void getLuaInterface(lua_State* L);
	void update(double dt);

	int resetVideoMode(int screenWidth, int screenHeight, bool fullscreen);

	///////////////////////////////////////////////////////
	// interface stuff moved from LuaLink in k2
	///////////////////////////////////////////////////////

	// SetVideoMode(w, h, fullscreen)
	static int li_setVideoMode(lua_State* L);

	// SetLayerParallax(avID, layer, invparallax)
	static int setLayerParallax(lua_State* L);

	// int LoadTexture(filename, slot)
	static int loadTexture(lua_State* L);

	// int CreateSubTexture(srcTexture, slot, x, y, w, h)
	static int createSubTexture(lua_State* L);

	// int CreateConcreteViewport()
	static int createConcreteViewportLua(lua_State* L);

	// int CreateAbstractViewport()
	static int createAbstractViewportLua(lua_State* L);

	// LinkViewports(vp1ID, vp2ID)
	static int linkViewportsLua(lua_State* L);

	// SetConcreteViewportPosition(vpID, x, y, w, h)
	static int setConcreteViewportPosition(lua_State* L);

	// SetAbstractViewportPosition(vpID, x, y, w, h)
	static int setAbstractViewportPosition(lua_State* L);

	// int CreateRenderObject(targetRenderer, maxB, maxI, maxF)
	static int createRenderObjectLua(lua_State* L);

	// DestroyRenderObject(slot)
	static int destroyRenderObjectLua(lua_State* L);

	// SetROPosition(slot, x, y, theta)
	static int setROPosition(lua_State* L);

	// SetRODims(slot, width, height)
	static int setRODims(lua_State* L);

	// SetROLayer(slot, layer)
	static int setROLayer(lua_State* L);

	// SetROByte(slot, bindex, b)
	static int setROByte(lua_State* L);

	// SetROInt(slot, iindex, i)
	static int setROInt(lua_State* L);

	// SetROFloat(slot, findex, f)
	static int setROFloat(lua_State* L);

	// SetROGroup(slot, g)
	static int setROGroup(lua_State* L);

	// SetROBits(slot, bits)
	static int setROBits(lua_State* L);


	////////////////////////////////
	// old k2 stuff
	////////////////////////////////
	Renderer** getRenderers();

	RenderObject* getRenderObject(int roID){return _renderObjects[roID];}
	GraphicsInternals* getInternals(){ return _gInternals; }
	AbstractViewport* getAbstractViewport(int avID){ return _abstractViewports[avID]; }
	ConcreteViewport* getConcreteViewport(int cvID){ return _concreteViewports[cvID]; }

	int createRenderObject(int renderTarget, int maxB, int maxI, int maxF);
	void destroyRenderObject(int roID);
	void destroyLocalRenderObject(int roID);
	void removeRenderObjectFromLiveList(int roID);

	int createAbstractViewport();
	void destroyAbstractViewport(int avpID);

	int createConcreteViewport();
	void destroyConcreteViewport(int cvpID);

	int createLocalViewportLink(int abstractID, int concreteID);
	void destroyViewportLink(int vplID);

	void sortObjectsIntoViewports();
	void updateGraphics(double dt);
};

}
#endif